#include <php.h>
#include "bcm2835.h"
#include "bcm_gpio.h"

void gpio_reset(void)
{
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_03, BCM2835_GPIO_PUD_OFF);
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_05, BCM2835_GPIO_PUD_OFF);
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_07, BCM2835_GPIO_PUD_OFF);
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_26, BCM2835_GPIO_PUD_OFF);
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_24, BCM2835_GPIO_PUD_OFF);
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_21, BCM2835_GPIO_PUD_OFF);
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_19, BCM2835_GPIO_PUD_OFF);
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_23, BCM2835_GPIO_PUD_OFF);
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_10, BCM2835_GPIO_PUD_OFF);
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_11, BCM2835_GPIO_PUD_OFF);
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_12, BCM2835_GPIO_PUD_OFF);
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_13, BCM2835_GPIO_PUD_OFF);
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_15, BCM2835_GPIO_PUD_OFF);
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_16, BCM2835_GPIO_PUD_OFF);
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_18, BCM2835_GPIO_PUD_OFF);
	bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_22, BCM2835_GPIO_PUD_OFF);

	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_INPT);
	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_INPT);
	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_07, BCM2835_GPIO_FSEL_INPT);
	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_26, BCM2835_GPIO_FSEL_INPT);
	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_24, BCM2835_GPIO_FSEL_INPT);
	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_21, BCM2835_GPIO_FSEL_INPT);
	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_19, BCM2835_GPIO_FSEL_INPT);
	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_23, BCM2835_GPIO_FSEL_INPT);
	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_10, BCM2835_GPIO_FSEL_INPT);
	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_11, BCM2835_GPIO_FSEL_INPT);
	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_12, BCM2835_GPIO_FSEL_INPT);
	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_13, BCM2835_GPIO_FSEL_INPT);
	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_15, BCM2835_GPIO_FSEL_INPT);
	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_16, BCM2835_GPIO_FSEL_INPT);
	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_18, BCM2835_GPIO_FSEL_INPT);
	bcm2835_gpio_fsel(RPI_V2_GPIO_P1_22, BCM2835_GPIO_FSEL_INPT);
}


PHP_FUNCTION(gpio_bcm_pin_reset)
{
    if (!bcm2835_init())
    {
        RETURN_LONG(-1);
    }

    gpio_reset();

    bcm2835_close();

    RETURN_LONG(0);
}


/**
  pin_no:
  pull:
  pin_mode:
  return integer
    0 for ok
   -1 for bcm2835_init error
   -2 for mode error
*/
PHP_FUNCTION(gpio_bcm_pin_ctrl)
{
    long pin_no = NO_PIN;
    long pin_mode = MODE_READ;
    long pull= NO_PULL;

    uint8_t data = 0;
    uint8_t pin = NO_PIN;

    if (!bcm2835_init())
    {
        RETURN_LONG(-1);
        return;
    }

    ZEND_PARSE_PARAMETERS_START(3, 3)
        Z_PARAM_LONG(pin_no)
        Z_PARAM_LONG(pin_mode)
        Z_PARAM_LONG(pull)
    ZEND_PARSE_PARAMETERS_END();

//    printf("Mode %d\n", pin_mode);
//    printf("Pull %d\n", pull);
//    printf("Pin Number %d\n", pin_no);

    switch (pin_no)
    {
        case 3:
	        pin = RPI_V2_GPIO_P1_03;
	        break;
        case 5:
	        pin = RPI_V2_GPIO_P1_05;
	        break;
        case 7:
	        pin = RPI_V2_GPIO_P1_07;
	        break;
        case 26:
	        pin = RPI_V2_GPIO_P1_26;
	        break;
        case 24:
	        pin = RPI_V2_GPIO_P1_24;
	        break;
        case 21:
	        pin = RPI_V2_GPIO_P1_21;
	        break;
        case 19:
	        pin = RPI_V2_GPIO_P1_19;
	       break;
        case 23:
	        pin = RPI_V2_GPIO_P1_23;
	        break;
        case 10:
	        pin = RPI_V2_GPIO_P1_10;
	        break;
        case 11:
	        pin = RPI_V2_GPIO_P1_11;
	        break;
        case 12:
	        pin = RPI_V2_GPIO_P1_12;
	        break;
        case 13:
	        pin = RPI_V2_GPIO_P1_13;
	        break;
        case 15:
	        pin = RPI_V2_GPIO_P1_15;
	        break;
        case 16:
	        pin = RPI_V2_GPIO_P1_16;
	        break;
        case 18:
	        pin = RPI_V2_GPIO_P1_18;
	        break;
        case 22:
	        pin = RPI_V2_GPIO_P1_22;
	        break;
	    default:
	        pin = NO_PIN;
    }

    switch (pull)
    {
        case PULL_UP:
            bcm2835_gpio_set_pud(pin, BCM2835_GPIO_PUD_UP);
            break;
        case PULL_DOWN:
            bcm2835_gpio_set_pud(pin, BCM2835_GPIO_PUD_DOWN);
            break;
        case NO_PULL:
            bcm2835_gpio_set_pud(pin, BCM2835_GPIO_PUD_OFF);
            break;
        default:
		    bcm2835_gpio_set_pud(pin, BCM2835_GPIO_PUD_OFF);
    }

    switch (pin_mode)
    {
    	case MODE_READ:
	        data = bcm2835_gpio_lev(pin);
	        RETURN_LONG(data);
	        return;
    	case MODE_INPUT_READ:
	        bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_INPT);
	        data = bcm2835_gpio_lev(pin);
	        RETURN_LONG(data);
	        return;
    	case MODE_SET:
	        bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);
	        bcm2835_gpio_set(pin);
	        break;
    	case MODE_CLR:
	        bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);
	        bcm2835_gpio_clr(pin);
	        break;
	    default:
            RETURN_LONG(-2);
            return;
    }

//    if (debug_mode == DEBUG_ON) {
//    	printf("Mode %d\n", pin_mode);
//    	printf("Pull %d\n", pull);
//    	printf("Pin Number %d\n", pin_no);
//    }

    bcm2835_close();

    RETURN_LONG(0);
}
